package main

import (
	"crypto/md5"
	"fmt"
	"goEmail/config"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"gopkg.in/gomail.v2"
)

func main() {

	fmt.Println("设置： config配置")
	config.ConfigInit()

	// 获取到 发送邮件
	var emails []string
	for _, user := range config.C.Users {
		emails = append(emails, user.Email)
		fmt.Println(user.Email)
	}

	if len(emails) == 0 {
		fmt.Println("没有发送邮箱")
		return
	}

	if len(config.C.Urls) == 0 {
		fmt.Println("没有配置URL")
		return
	}

	// 打开文件，如果文件不存在则创建，使用追加模式
	file, err := os.OpenFile(config.C.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// 进行请求检测服务
	var content string
	for _, url := range config.C.Urls {
		flag, _, logStr := SendGet(url, file)
		if flag == false {
			content += "<h1>" + logStr + " 检测时间:" + time.Now().Format("2006-01-02 15:04:05") + "</h1>\n"
			if url.Cmd != "" && len(url.Cmd) > 2 {
				fmt.Println("运行 cmd " + url.Cmd + "\n")
				RunCmd(url.Cmd, file)
			}
		}
		fmt.Println(flag)
	}
	fmt.Println(content)

	if content != "" {
		fmt.Println("发送邮件", config.C.Send.Subject, content, emails, file)
		SendEmail(config.C.Send.Subject, content, emails, file)
	}
}

// 发送请求
func SendGet(urls config.ConfigUrls, file *os.File) (flag bool, t uint64, logStr string) {
	logStr = "项目：" + urls.Remark + " <p>请求地址：" + urls.Url + " </p>"

	url := urls.Url
	// 判断是否需要签名
	if urls.Key != "" {
		timeNow := time.Now()
		minValue := timeNow.Minute()
		minStr := fmt.Sprint(minValue)
		if minValue < 10 {
			minStr = "0" + minStr
		}
		year := timeNow.Year()
		signStr := minStr + urls.Key + fmt.Sprint(int64(math.Floor(float64(year*minValue/999)))%3)
		url += MD5(signStr)
	}

	// 时间戳 毫秒
	sT := time.Now().UnixMilli()
	// 发送GET请求
	resp, err := http.Get(url)
	fmt.Println(url)
	if err != nil {
		// log.Fatalf("Failed to send GET request: %v", err)
		logStr += "请求失败 建立不到连接"
		file.WriteString(logStr + "\n")
		return
	}
	defer resp.Body.Close()

	// 读取 status 状态码
	status := resp.StatusCode
	fmt.Println("status:", status)
	if status != 200 && status != 401 && status != 404 {
		logStr += "请求失败 状态码:" + fmt.Sprint(status)
		file.WriteString(logStr + "\n")
		return
	}

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// log.Fatalf("Failed to read response body: %v", err)
		logStr += "请求失败 读取响应体失败"
		file.WriteString(logStr + "\n")
		return
	}

	// 打印响应体
	log.Println(string(body))
	file.WriteString(urls.Url + " 响应体:" + string(body) + "\n")
	eT := time.Now().UnixMilli()
	t = uint64(eT - sT)
	if t > urls.Time {
		logStr += "请求超时 耗时: " + fmt.Sprint(t) + " 设定时间:" + fmt.Sprint(urls.Time)
		file.WriteString(logStr + "\n")
		return
	}
	logStr += "ok 耗时:" + fmt.Sprint(t)
	flag = true
	return
}

// 发送邮件
func SendEmail(subject string, content string, emails []string, file *os.File) {
	m := gomail.NewMessage()
	//发送人
	m.SetHeader("From", config.C.Send.Email)
	//接收人
	m.SetHeader("To", emails...)
	//抄送人
	//m.SetAddressHeader("Cc", "xxx@qq.com", "xiaozhujiao")
	//主题
	m.SetHeader("Subject", subject)
	//内容
	m.SetBody("text/html", content)
	//附件
	//m.Attach("./myIpPic.png")

	//拿到token，并进行连接,第4个参数是填授权码
	// qq smtp.qq.com, 587
	// 企业微信 smtp.exmail.qq.com 465
	d := gomail.NewDialer(config.C.Send.Host, config.C.Send.Port, config.C.Send.Email, config.C.Send.Token)

	// 发送邮件
	if err := d.DialAndSend(m); err != nil {
		fmt.Printf("DialAndSend err %v:", err)
		file.WriteString(" 发送邮件失败 时间:" + time.Now().Format("2006-01-02 15:04:05") + "\n")
		panic(err)
	}
	file.WriteString(" 发送邮件成功时间:" + time.Now().Format("2006-01-02 15:04:05") + "\n")
	fmt.Printf("send mail success\n")
}

func MD5(str string) string {
	data := []byte(str) //切片
	has := md5.Sum(data)
	md5str := fmt.Sprintf("%x", has) //将[]byte转成16进制
	return md5str
}

func RunCmd(cmdStr string, file *os.File) {
	file.WriteString(" 重启服务: " + cmdStr + " 时间:" + time.Now().Format("2006-01-02 15:04:05") + "\n")
	// 将命令字符串分割成一个字符串数组
	args := strings.Split(cmdStr, " ")

	// 创建一个*Cmd结构体实例
	execCmd := exec.Command(args[0], args[1:]...)

	// 运行命令并获取输出
	output, err := execCmd.Output()

	// 检查是否有错误
	if err != nil {
		fmt.Printf("Error executing command: %s\n", err)
		return
	}

	fmt.Println("Command output:", string(output)+"\n")

	// 打印命令输出
	file.WriteString(" 命令输出: " + string(output) + "\n")
}
